package com.wmh.baseservice.common.controller;

import com.alibaba.fastjson.JSONObject;
import com.wmh.baseservice.common.ex.ServiceException;
import com.wmh.baseservice.common.utils.CommUtil;
import com.wmh.baseservice.common.utils.returnbody.Code;
import com.wmh.baseservice.common.utils.returnbody.ResultCodeInfo;
import com.wmh.baseservice.common.utils.returnbody.ReturnBody;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.SchedulerException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolationException;


/**
 * @author: xy
 * @Date: 2021-10-26 16:10
 * @describe: 全局异常捕获
 */
@RestController
@ControllerAdvice
public class ExceptionCaptureReturnController {

    /**
     * shiro无权操作返回
     */
    @ExceptionHandler(UnauthorizedException.class)
    public String unauthorizedException(HttpServletResponse response,UnauthorizedException e){
        e.printStackTrace();
        response.setStatus(403);
        if (e.getMessage().contains("Subject does not have role")){
            return ReturnBody.error(ResultCodeInfo.NO_AUTHORITY_OPERATE_ROLE);
        }else {
            return ReturnBody.error(ResultCodeInfo.NO_AUTHORITY_OPERATE_PERMISSION);
        }
    }


    @ExceptionHandler(ServiceException.class)
    public String serviceException(ServiceException e){
        System.err.println("业务模块异常: "+ e.getMessage());
        e.printStackTrace();
        String message = e.getMessage();
        if (CommUtil.checkNull(message)) {
            try {
                JSONObject jsonObject = JSONObject.parseObject(message);
                return ReturnBody.error(jsonObject.getInteger("code"), jsonObject.getString("result"));
            }catch (Exception ex){
                return ReturnBody.error(Code.SYS_EXCEPTION, message);
            }
        }else {
            return ReturnBody.error(ResultCodeInfo.SYS_EXCEPTION);
        }
    }

    /** 参数绑定异常 : 即 validation 校验封装的参数不合格*/
    @ExceptionHandler({BindException.class})
    public String valueBindExceptionHandler(BindException e){
        return ReturnBody.error(Code.PARAM_ERROR,e.getBindingResult().getFieldError().getDefaultMessage());
    }

    /** 方法参数无效异常 : 即 validation 校验封装的参数不合格*/
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public String methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
        return ReturnBody.error(Code.PARAM_ERROR,e.getBindingResult().getFieldError().getDefaultMessage());
    }

    /** 参数违规约束 : 即 validation 校验 controller 上的参数 违规
     *  并且 由于此异常会将错误信息 'message' 存在异常的message里 ,
     *  当满足异常为多个时,message里的异常为多异常
     *  所可以要进行切割才能返回
     * */
    @ExceptionHandler(ConstraintViolationException.class)
    public String valueViolationExceptionHandler(ConstraintViolationException e){
        String[] split = e.getMessage().split(",");
        String message = split.length > 1 ?
                split[0].split(":")[1] :
                e.getMessage().split(":")[1];

        return ReturnBody.error(Code.PARAM_ERROR,message);
    }

    @ExceptionHandler(UnauthenticatedException.class)
    public String unauthenticatedException(HttpServletResponse response,UnauthenticatedException e){
        e.printStackTrace();
        response.setStatus(401);
        return ReturnBody.error(ResultCodeInfo.TOKEN_EXPIRE);
    }

    @ExceptionHandler(RedisConnectionFailureException.class)
    public String redisConnectionFailureException(){
        return ReturnBody.error("未能连接到Redis服务，为保证服务性能请检查连接后重试");
    }

    @ExceptionHandler(SchedulerException.class)
    public String schedulerException(SchedulerException e){
        String msg;
        if (e.getMessage().contains("will never fire")){
            msg = "您配置的任务永远都不会被执行";
        }else if (e instanceof ObjectAlreadyExistsException){
            msg = "该定时任务已经启动";
        } else {
            msg = e.getMessage();
        }
        return ReturnBody.error(msg);
    }

    @ExceptionHandler(Exception.class)
    public String allException(Exception e){
        e.printStackTrace();
        return ReturnBody.error(ResultCodeInfo.SYS_EXCEPTION);
    }


}
